package antoine.ear.exo;

import java.lang.reflect.Constructor;
import java.util.ArrayList;

import javax.sound.midi.MetaMessage;
import javax.sound.midi.MidiEvent;
import javax.sound.midi.Sequence;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Track;
import javax.swing.JCheckBox;

import antoine.ear.generator.ChordGenerator;
import antoine.ear.generator.chords.Dom7Generator;
import antoine.ear.generator.chords.Dom7OnzeDieseGenerator;
import antoine.ear.generator.chords.Maj7Generator;
import antoine.ear.generator.chords.Min7Generator;
import antoine.ear.generator.chords.MinMaj7Generator;
import antoine.ear.generator.chords.Sus4Generator;

public abstract class Exo {

	private static final int VELOCITY = 64;
	public static final int ACTIVATENOTE = 10;
	public static final int DESACTIVATENOTE = 9;
	public static final int CLEAR = 11;

	private Sequence sequence;
	protected int tempo;
	protected int octave;
	public String soluce = "";
	public String indication = "";

	public Exo() {
		try {

		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}

	public Exo(int tempo, int octave) {
		try {
			this.tempo = tempo;
			this.octave = octave;
			generate();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(-1);
		}
	}

	public Sequence getSequence() {
		return sequence;
	}

	public void setSequence(Sequence sequence) {
		this.sequence = sequence;
	}

	public abstract String getPrintableResult();

	public abstract String getIndication();

	public abstract void generate() throws Exception;

	protected MidiEvent createNoteOnEvent(int nKey, long lTick) {
		return createNoteEvent(ShortMessage.NOTE_ON, nKey, VELOCITY, lTick);
	}

	protected MidiEvent createNoteOffEvent(int nKey, long lTick) {
		return createNoteEvent(ShortMessage.NOTE_OFF, nKey, 0, lTick);
	}

	protected MidiEvent createNoteEvent(int nCommand, int nKey, int nVelocity,
			long lTick) {
		ShortMessage message = new ShortMessage();
		try {
			message.setMessage(nCommand, 0, nKey, nVelocity);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		MidiEvent event = new MidiEvent(message, lTick);
		return event;
	}

	protected MidiEvent createMetaMessOnEvent(int nKey, long lTick, int type) {
		MetaMessage message = new MetaMessage();
		try {
			byte[] tab = new byte[1];
			tab[0] = (byte) nKey;
			message.setMessage(type, tab, 1);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		MidiEvent event = new MidiEvent(message, lTick);
		return event;
	}

	public void setTempo(int bpm) {
		this.tempo = bpm;

		Track track = this.getSequence().getTracks()[0];
		final int TEMPO = 0x51;
		int tempoInMPQ = bpm * 20000;
		byte[] data = new byte[3];
		data[0] = (byte) ((tempoInMPQ >> 16) & 0xFF);
		data[1] = (byte) ((tempoInMPQ >> 8) & 0xFF);
		data[2] = (byte) (tempoInMPQ & 0xFF);

		MetaMessage message = new MetaMessage();
		try {
			message.setMessage(TEMPO, data, data.length);
			MidiEvent event = new MidiEvent(message, 0);
			track.add(event);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}

	}

	public int getOctave() {
		return octave;
	}

	public void setOctave(int octave) {
		this.octave = octave;
	}

	public int getTempo() {
		return tempo;
	}

}
